/*
 * Digital Audio Mobile - A multi track studio for Windows Mobile
 * Copyright (C) 2008 David Olsson
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <aygshell.h>

#include "Composition.h"
#include "DamDialog.h"
#include "Segment.h"
#include "Track.h"
#include "TrackRollControl.h"

using namespace std;

TrackRollControl::TrackRollControl(DamDialog *parent, unsigned int height, Composition *composition) throw(): Control(parent, 0, 0, parent->width(), height), m_hTimeScroll(0), m_hContextMenu(0), m_composition(composition), m_currTrack(0), m_viewEnd(DEFAULTVISIBLEMEASURE * composition->beatsPerMeasure(), composition->beatsPerMinute(), composition->beatsPerMeasure(), composition->beatNoteType()) {
    m_hTimeScroll = CreateWindow(TEXT("SCROLLBAR"), 0, WS_CHILD | WS_DISABLED | WS_VISIBLE | SBS_HORZ, -1, Dialog::heightToPixels(Control::height() - 8), Dialog::widthToPixels(width()) + 2, Dialog::heightToPixels(8), hWnd(), 0, parent->hInstance(), 0);

    m_hContextMenu = CreatePopupMenu();
    AppendMenu(m_hContextMenu, MF_ENABLED | MF_STRING, 1, TEXT("Add track"));
    AppendMenu(m_hContextMenu, MF_ENABLED | MF_STRING, 2, TEXT("Remove track..."));
    AppendMenu(m_hContextMenu, MF_SEPARATOR, 0, 0);
    AppendMenu(m_hContextMenu, MF_ENABLED | MF_STRING, 3, TEXT("Move"));
    AppendMenu(m_hContextMenu, MF_ENABLED | MF_STRING, 4, TEXT("Delete"));
    AppendMenu(m_hContextMenu, MF_ENABLED | MF_STRING, 5, TEXT("Scissors"));
}

void TrackRollControl::resetSongPosition() throw() {
    m_marker = MusicTime();
    InvalidateRect(hWnd(), 0, TRUE);
}

void TrackRollControl::updateSongPosition(const MusicTime &dT) throw() {
    m_marker += dT;
    static_cast<DamDialog *>(parent())->updateSongPosition(m_marker);
    InvalidateRect(hWnd(), 0, TRUE);
}

const MusicTime &TrackRollControl::currentSongPosition() const throw() {
    return(m_marker);
}

const Track *TrackRollControl::currentTrack() const throw() {
    return(m_currTrack);
}

Track *TrackRollControl::currentTrack() throw() {
    return(m_currTrack);
}

void TrackRollControl::paint(HDC hDc) const throw() {
    // Draw the time ruler.
    SetBkMode(hDc, TRANSPARENT);
    RECT timeRect = {0, 0, Dialog::widthToPixels(width()), Dialog::heightToPixels(12)};
    FillRect(hDc, &timeRect, GetSysColorBrush(COLOR_3DFACE));
    MoveToEx(hDc, 0, Dialog::heightToPixels(12) - 1, 0);
    LineTo(hDc, Dialog::widthToPixels(width()), Dialog::heightToPixels(12) - 1);
    MusicTime dT(m_composition->beatsPerMeasure(), m_composition->beatsPerMinute(), m_composition->beatsPerMeasure(), m_composition->beatNoteType());
    unsigned int measure = (m_viewStart.toMilliseconds() / MusicTime(m_composition->beatsPerMeasure(), m_composition->beatsPerMinute(), m_composition->beatsPerMeasure(), m_composition->beatNoteType()).toMilliseconds()) + 1;
    for(MusicTime time = m_viewStart.quantisize(1, m_composition->beatsPerMinute(), m_composition->beatsPerMeasure(), m_composition->beatNoteType()); time < m_viewEnd; time += dT) {
        int pos = Dialog::widthToPixels((width() * (time - m_viewStart).toMilliseconds()) / (m_viewEnd - m_viewStart).toMilliseconds());
        MoveToEx(hDc, pos, 4, 0);
        LineTo(hDc, pos, Dialog::heightToPixels(12));

        TCHAR buf[32];
        wsprintf(buf, TEXT("%d"), measure);
        ExtTextOut(hDc, pos + Dialog::widthToPixels(1), 4, 0, 0, buf, _tcslen(buf), 0);
        measure += 1;
    }

    // Draw the tracks and segments.
    if(!m_composition->tracks().empty()) {
        unsigned int trackHeight = (height() - 12 - 8) / m_composition->tracks().size();
        if(trackHeight > 32) {
            trackHeight = 32;
        }
        unsigned int y = 12;
        for(list<Track *>::const_iterator iter = m_composition->tracks().begin(); iter != m_composition->tracks().end(); iter++) {
            // Draw the track and its segments.
            RECT trackRect = {0, Dialog::heightToPixels(y), Dialog::widthToPixels(width()), Dialog::heightToPixels(y + trackHeight) - 1};
            if(*iter == m_currTrack) {
                FillRect(hDc, &trackRect, GetSysColorBrush(COLOR_INFOBK));
            }
            MoveToEx(hDc, 0, Dialog::heightToPixels(y + trackHeight) - 1, 0);
            LineTo(hDc, Dialog::widthToPixels(width()), Dialog::heightToPixels(y + trackHeight) - 1);

            for(list<Segment *>::const_iterator siter = (*iter)->segments().begin(); siter != (*iter)->segments().end(); siter++) {
                (*siter)->paint(hDc, (*iter == m_currTrack) ? (*iter)->brush() : (*iter)->unselectedBrush(), trackRect, m_viewStart, m_viewEnd);
            }

            // Draw the mute button.
            RECT muteRect = {Dialog::widthToPixels(2), Dialog::heightToPixels(y + 2), Dialog::widthToPixels(2 + 8), Dialog::heightToPixels(y + 2 + 8)};
            if((*iter)->muted()) {
                SelectObject(hDc, GetSysColorBrush(COLOR_3DFACE));
            }
            else {
                SelectObject(hDc, GetStockObject(HOLLOW_BRUSH));
            }
            RoundRect(hDc, muteRect.left, muteRect.top, muteRect.right, muteRect.bottom, Dialog::widthToPixels(2), Dialog::heightToPixels(2));
            DrawText(hDc, TEXT("M"), 1, &muteRect, DT_CENTER | DT_VCENTER | DT_NOCLIP);

            y += trackHeight;
        }
    }

    // Draw the marker.
    if(m_marker >= m_viewStart && m_marker <= m_viewEnd) {
        int pos = Dialog::widthToPixels((width() * (m_marker - m_viewStart).toMilliseconds()) / (m_viewEnd - m_viewStart).toMilliseconds());
        MoveToEx(hDc, pos, 0, 0);
        LineTo(hDc, pos, Dialog::heightToPixels(height() - 8));
    }
}

void TrackRollControl::controlNotification(HWND hCtrl, WPARAM notification) throw() {
}

void TrackRollControl::click(unsigned int x, unsigned int y) throw() {
    if(y < 12) {
        // Click on the time ruler. Move the marker.
        m_marker = (m_viewStart + ((x * (m_viewEnd - m_viewStart).toMilliseconds()) / width())).quantisize(4, m_composition->beatsPerMinute(), m_composition->beatsPerMeasure(), m_composition->beatNoteType());
        static_cast<DamDialog *>(parent())->updateSongPosition(m_marker);
        InvalidateRect(hWnd(), 0, TRUE);
    }
    else {
        // Click on the track roll.
        if(!m_composition->tracks().empty()) {
            unsigned int trackY = y;
            // Did we select a track?
            m_currTrack = 0;
            unsigned int trackHeight = (height() - 12) / m_composition->tracks().size();
            if(trackHeight > 32) {
                trackHeight = 32;
            }
            trackY -= 12;
            trackY /= trackHeight;
            unsigned int clickY = y - 12 + trackHeight;
            if(trackY < m_composition->tracks().size()) {
                for(list<Track *>::iterator iter = m_composition->tracks().begin(); trackY != static_cast<unsigned int>(-1); iter++) {
                    m_currTrack = *iter;
                    trackY -= 1;
                    clickY -= trackHeight;
                }

                // Check if we clicked the mute button.
                if((x >= 2 && x <= 10) && (clickY >= 2 && clickY <= 10)) {
                    m_currTrack->toggleMute();
                }
            }

            static_cast<DamDialog *>(parent())->setCurrentTrack(m_currTrack);
            SetFocus(hWnd());
            InvalidateRect(hWnd(), 0, TRUE);
        }

        // Check if we're opening a popup menu.
        SHRGINFO shrgi;
        shrgi.cbSize  = sizeof(SHRGINFO);
        shrgi.hwndClient = hWnd();
        shrgi.ptDown.x = Dialog::widthToPixels(x);
        shrgi.ptDown.y = Dialog::heightToPixels(y);
        shrgi.dwFlags = SHRG_RETURNCMD;
        if(SHRecognizeGesture(&shrgi) == GN_CONTEXTMENU) {
            EnableMenuItem(m_hContextMenu, 2, (m_currTrack == 0) ? (MF_GRAYED) : (MF_ENABLED));

            switch(TrackPopupMenu(m_hContextMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, Dialog::widthToPixels(x), Dialog::heightToPixels(y), 0, hWnd(), 0)) {
                case 1:
                    m_currTrack = m_composition->addTrack();
                    static_cast<DamDialog *>(parent())->setCurrentTrack(m_currTrack);
                    SetFocus(hWnd());
                    InvalidateRect(hWnd(), 0, TRUE);
                    break;
                case 2:
                    if(MessageBox(hWnd(), TEXT("Are you sure you want to remove the selected track and all its audio segments?"), TEXT("Remove track?"), MB_OKCANCEL | MB_ICONQUESTION) == IDOK) {
                        m_composition->removeTrack(m_currTrack);
                        m_currTrack = 0;
                        static_cast<DamDialog *>(parent())->setCurrentTrack(m_currTrack);
                        InvalidateRect(hWnd(), 0, TRUE);
                    }
                    break;
            }
        }
    }
}

const unsigned int TrackRollControl::DEFAULTVISIBLEMEASURE = 8;
